//--------------------------------------------------------------------------
// $Id: DigestXorDHCrypto.java 10 2006-08-21 13:48:09Z zendragon $
//--------------------------------------------------------------------------
// Copyright 2006 Social Brain Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//--------------------------------------------------------------------------

package org.socialbrain.openid.security;

import org.socialbrain.openid.OpenIdException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author <a href="http://erning.net/">Zhang Erning</a>
 * @version $Id: DigestXorDHCrypto.java 10 2006-08-21 13:48:09Z zendragon $
 */
public class DigestXorDHCrypto implements DHCrypto
{
    public boolean isAcceptSessionType(String sessionType)
    {
        return StringUtils.equals(_acceptedSessionType, sessionType);
    }

    public boolean isAcceptAssocType(String assocType)
    {
        return StringUtils.equals(_acceptedAssocType, assocType);
    }

    public byte[] encrypt(byte[] source, DHKeyPair keyPair, BigInteger peerPublicKey)
    {
        return xor(source, keyPair, peerPublicKey);
    }

    public byte[] decrypt(byte[] source, DHKeyPair keyPair, BigInteger peerPublicKey)
    {
        return xor(source, keyPair, peerPublicKey);
    }

    protected byte[] xor(byte[] source, DHKeyPair keyPair, BigInteger peerPublicKey)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance(_digestAlgorithm);
            byte[] target = md.digest(keyPair.computeSecretKey(peerPublicKey).toByteArray());
            if (target.length != source.length)
            {
                throw new OpenIdException("The length of shared key and digest should be equals");
            }
            for (int i = 0; i < target.length; i++)
            {
                target[i] ^= source[i];
            }
            return target;
        }
        catch (OpenIdException e)
        {
            throw e;
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new OpenIdException(String.format("Digest algorithm %s is not supported", _digestAlgorithm), e);
        }
        catch (Exception e)
        {
            throw new OpenIdException("crypt fail", e);
        }
    }

    //

    @Override
    public String toString()
    {
        return String.format("AcceptedAssocType: %s, AcceptedSessionType: %s, DigestAlgorithm: %s",
                _acceptedAssocType, _acceptedSessionType, _digestAlgorithm);
    }

    //

    public void setAcceptedSessionType(String value)
    {
        _acceptedSessionType = value;
    }

    public String getAcceptedSessionType()
    {
        return _acceptedSessionType;
    }

    public void setAcceptedAssocType(String value)
    {
        _acceptedAssocType = value;
    }

    public String getAcceptedAssocType()
    {
        return _acceptedAssocType;
    }

    public void setDigestAlgorithm(String value)
    {
        _digestAlgorithm = value;
    }

    public String getDigestAlgorithm()
    {
        return _digestAlgorithm;
    }

    private String _acceptedSessionType;
    private String _acceptedAssocType;
    private String _digestAlgorithm;

    private transient static final Log _logger = LogFactory.getLog(DigestXorDHCrypto.class);
}
